# views.py

import pdb

from django.contrib.auth.models import UserManager, User
from django.contrib.auth import login, authenticate
from django.forms.formsets import formset_factory
from django.shortcuts import render_to_response
from django.core.mail import mail_managers
from django.template import RequestContext

from django.http import Http404, HttpResponse

import urllib

import logging
viewslogger = logging.getLogger('psd.register.views')

from psd.register.forms import PersonForm, RegRecordForm
from psd.register.models import Person, RegRecord, LOCATIONS, Event

from psd.settings import DEBUG



def psdid_stamp_user(p):
    """Give a PSD ID to the person and enter that into the database"""
    id = mk_person_id(p)
    p.psdid = id
    p.save()

def contact_reg(g, evt, request ):
    """
    Email the contact email with event details, etc.
    If the user account does not exist, build it and send the password along 
    with everything else
    """
    newuser = False
    if not request.user.is_authenticated():
        newuser = True
        if DEBUG:
            ## WARNING: passwords are PSD IDs in debug mode.  Watch this before distribution.
            pw = g.psdid 
        else:
            pw = UserManager().make_random_password()
        user = User.objects.create_user(g.psdid, g.email, pw)
        user = authenticate(username=g.psdid, password=pw)
        login(request, user)
    else:
        user = request.user
        pw = 'XXXXX'
        
    ## You can call email_user with args (subject, message, sender).
    ## If you leave out the sender, like here, it fills in the
    ## DEFAULT from settings.py
    #if request == None:
    #    email_body = render_to_response( 'registration_email.txt', {'rr' : g, 'event' : evt, 'newuser' : newuser, 'password' : pw } )
    #else:
    email_body = render_to_response( 'registration_email.txt', 
                                         {'rr' : g, 'event' : evt, 'newuser' : newuser, 'password' : pw }, 
                                         context_instance=RequestContext(request) )
        
    #user.email_user( "Registration confirmation for %s." % g.psdid, email_body.content )
    admin_email_body = render_to_response( 'payment_email.txt', { 'rr': g, 'data':'no data--not from paypal'} )
    #mail_managers( 'Registration for %s' % (g.psdid,), admin_email_body.content )
    viewslogger.debug( "Registered new person %s" % (g.psdid,) )

    g.save()

    
def add_group(g):
    """Take new regrecord g and give all people in it their PSD IDs and then generate a 
       group PSD ID by copying the one from the person (if there is only one) or making 
       one from the names of all the people in the group
       
       Also make a user account for the PSDID of the regrecord"""
    members = g.people.all()

    for p in members:
        psdid_stamp_user(p)
    if len(members) == 1:
        g.psdid = members[0].psdid
    else:
        id = mk_group_id(g)
        g.psdid = id
     


def mk_person_id(p):
    """ Make a Poly Speed Dating ID, i.e., the initials of the person followed by a 
        three digit number"""
    bignum = 100 + p.id
    id = p.first_name[0] + p.last_name[0] + str(bignum)
    return id.upper()

def mk_group_id(g):
    """ Make a PSD ID for a group by taking the first letter of each name and then
        adding a three digit number and a following G for group"""
    bignum = 100 + g.id
    initials = [p.first_name[0] for p in g.people.all()]
    initials = ''.join(initials)
    id = initials + str(bignum) + 'G'
    return id.upper()






def admin_checkboxes(request):
    PersonFormset = formset_factory(PersonForm)
    if request.method == 'POST':
        pformset = PersonFormset(request.POST)
        #if pformset.is_valid():
            

def set_hidden_reg_fields(rcd):
    """ Initialize various flags for payment and whatnot that users don't directly
        fill out."""
    for field in ['paid', 'cancelled', 'pending', 'here', 'stationary', 'is_group']:
        rcd[field] = False
    for field in ['geek_code', 'notes']:
        rcd[field] = ''
    for field in ['matches', 'oneway']:
        rcd[field] = 0


def tryUpdateFromOldForm(newreg):
    """Look for an old form for the same event.  If it is there, copy the admin
    fields over, delete the old form, save the new form"""
    oldreg = RegRecord.objects.filter(psdid=newreg.psdid).filter(event=newreg.event)
    if len(oldreg) >= 1:
        oldreg = oldreg[0]
        for field in ['paid', 'cancelled', 'pending', 'here', 'stationary', 'is_group', 'notes','matches', 'oneway']:
            newreg.__dict__[field] = oldreg.__dict__[field]
           
        # delete old records with the same event.
        RegRecord.objects.filter(event=newreg.event).filter(psdid=newreg.psdid).exclude(id=newreg.id).delete()
        newreg.reregistered=True
    else:
        newreg.reregistered=False




def sign_up_indiv(request, event_name):
    """Called when the Individual Registration form is filled out and 
       submitted."""
    
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "Sorry.  You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

    # reg closed code.  Where does this go?
    #if not request.user.is_authenticated():
    #return render_to_response( 'regclosed.html' );

    if request.method == 'POST':
        pform = PersonForm(request.POST)
        rform = RegRecordForm(request.POST)
        if pform.is_valid() and rform.is_valid():
            pcd = pform.cleaned_data
            rcd = rform.cleaned_data
            if request.user.is_authenticated():
                # overwrite associate person object
                oldreg = RegRecord.objects.filter(psdid=request.user.username)
                if len(oldreg) == 0:
                    # we don't have an associated person object.  I guess we make one
                    # and fail silently?  Ick.   (We didn't toss a lack of regrecord
                    # in the original presentation of the form, below.)
                    p = Person(**pcd)
                else:
                    p = oldreg[0].people.all()
                    if len(p) > 0:
                        p = p[0]
                        del pcd['psdid']
                        p.__dict__.update(pcd)
                    else:
                        p = Person(**pcd)
            else:
                ## user not logged in, check if registration already exists
                oldemail = RegRecord.objects.filter(email=rcd['email']).count()
                if oldemail == 0:
                    ## no record of email - create new person
                    p = Person(**pcd)
                else:
                    ## email already registered and user not logged in, user needs to login.
                    return render_to_response('returningusererror.html', {'login_required' : 'yes' }, context_instance=RequestContext(request))
            p.save()

            set_hidden_reg_fields(rcd)
            rcd['event'] = event.event
            r = RegRecord(**rcd)
            r.save()
            r.people.add(p)
            r.save()
            if request.user.is_authenticated():
                r.psdid = request.user.username
                tryUpdateFromOldForm( r )
                r.save()
                contact_reg(r, event, request=request )
            else:
                add_group(r)
                contact_reg(r, event, request=request )
            return render_to_response('payment.html', {'reg': r},
                                       context_instance=RequestContext(request))
        else:
            return render_to_response('registration_error.html', {'pform': pform, 'rform': rform}, context_instance=RequestContext(request))
    elif request.user.is_authenticated():
            oldreg = RegRecord.objects.filter(psdid=request.user.username).order_by('-id')
            if len(oldreg) == 0:
                ## TODO: refactor to avoid repeating code from below.
                pform = PersonForm(initial={'seek_kinkiness': 'EI'})
                rform = RegRecordForm()
            else:
                oldreg = oldreg[0]
                rform = RegRecordForm(initial=oldreg.__dict__)
                oldper=oldreg.people.all()
                if len(oldper) > 0:
                    pform = PersonForm(initial=oldper[0].__dict__)
                else:
                    pform = PersonForm(initial={'seek_kinkiness': 'EI'})
#       except RegRecord.DoesNotExist:
    else:
        pform = PersonForm(initial={'seek_kinkiness': 'EI'})
        rform = RegRecordForm()
    return render_to_response('registerIndiv.html', {'event': event, 'pform': pform, 'rform': rform}, context_instance=RequestContext(request))




def registration_note(request, event_name="unknown"):
    """Called when note for registration is needed"""
    
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "Sorry.  You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

    return render_to_response( 'registration_note.html', {'event_name':event_name },
                               context_instance=RequestContext(request) )







def sign_up_group(request, event_name):
    """Called when the Group Registration form is filled out and 
       submitted."""
    
    try:
        event = Event.objects.get(event=event_name)
    except Event.DoesNotExist:
        return render_to_response( 'error.html', {'message' : "You are trying to register for an event that does not exist or is closed.  Please try again." }, 
                                   context_instance=RequestContext(request)  )

    #if not request.user.is_authenticated():
    #return render_to_response( 'regclosed.html' );

    PersonFormset = formset_factory(PersonForm, extra=3, max_num=3)

    # get old last record if user logged in and there is such a record
    if request.user.is_authenticated():
        oldreg = RegRecord.objects.filter(psdid=request.user.username).order_by('-id')
        if len(oldreg) == 0:
            oldreg = None
        else:
            oldreg = oldreg[0]
    else:
        oldreg = None 
  
    if request.method == 'POST':
        pformset = PersonFormset(request.POST)
        rform = RegRecordForm(request.POST)
        if pformset.is_valid() and rform.is_valid():
            
            rcd = rform.cleaned_data
            
            if oldreg is None:
                ## user not logged in, check if registration already exists
                oldemail = RegRecord.objects.filter(email=rcd['email']).count()
                if oldemail > 0:
                    ## email already registered and user not logged in, user needs to login.
                    return render_to_response('returningusererror.html', {'login_required' : 'yes' }, context_instance=RequestContext(request))

            set_hidden_reg_fields(rcd)
            rcd['event'] = event.event
            r = RegRecord(**rcd)
            r.save()
            
            if not oldreg is None:
                oldpeeps = oldreg.people.all()
                if len(oldpeeps) > len(pformset.forms):
                    return render_to_response( 'error.html', {'message' : "You are registering fewer people than the last time you registered (%d vs. %d).  This is currently not allowed.  Please log-out, register as a brand new user, and then contact us." % (len(oldpeeps), len(pformset.forms)) }, 
                                       context_instance=RequestContext(request)  )
                
                for (pform,p) in zip( pformset.forms, oldpeeps ):
                    if not pform.cleaned_data:
                        return render_to_response( 'error.html', {'message' : "Missing person in registration.  You are registering a different number of people than the last time you registered.  This is currently not allowed.  Please log-out, register as a brand new user, and then contact us." }, 
                                       context_instance=RequestContext(request)  )
                    pcd = pform.cleaned_data
                    del pcd['psdid']
                    p.__dict__.update(pcd)
                    p.save()
                    r.people.add(p)
                    p.save()
            else:
                for form in pformset.forms:
                    if not form.cleaned_data:
                        continue
                    pcd = form.cleaned_data
                    p = Person(**pcd)
                    p.save()
                    r.people.add(p)
                    p.save()

            if r.people.count() > 1:
                r.is_group = True
            r.save()
            
            if request.user.is_authenticated():
                r.psdid = request.user.username
                tryUpdateFromOldForm( r )
                r.save()
                contact_reg(r, event, request=request )
            else:
                add_group(r)
                contact_reg(r, event, request=request )
            return render_to_response('payment.html', {'reg': r},
                                       context_instance=RequestContext(request))
        else:
            return render_to_response('registration_error.html', {'pformset': pformset, 'rform': rform}, context_instance=RequestContext(request))
    elif not oldreg is None:
        rform = RegRecordForm(initial=oldreg.__dict__)
        oldper=oldreg.people.all()
        inits = []
        for op in oldper:
            inits.append(op.__dict__)
        pformset = PersonFormset( initial=inits )
    else:
        pformset = PersonFormset()
        rform = RegRecordForm()
    return render_to_response('registerGroup.html', {'event': event, 'pformset': pformset, 'rform': rform}, context_instance=RequestContext(request))






class PaypalPaymentEndpoint:
    
    verify_url = "https://www.paypal.com/cgi-bin/webscr"
       
    def __call__(self, request):
        viewslogger.debug( "PayPalPaymentEndpoint called request_meth = %s" % (request.method, ) )
        ret = None
        #data = { 'apple':20, 'pear':'banana'}
        if request.method == 'POST':
            data = dict(request.POST.items())
            viewslogger.debug( "got post from %s with data %s ", request.get_host(), data )
            # We need to post that BACK to PayPal to confirm it
            args = { 'cmd': '_notify-validate', }
            args.update(data)

            viewslogger.debug( "Validating ipn with Paypal at %s", self.verify_url)

            if urllib.urlopen(self.verify_url, urllib.urlencode(args)).read() == 'VERIFIED':
                cstring = "NO CUSTOM"
                if 'custon' in data:
                    cstring = data['custom']
                viewslogger.debug( "Got VERIFIED from paypal for %s with custom: %s", data['payer_email'], cstring )
                ret = self.valid_ipn(data)
            else:
                #TODO: email someone?
                viewslogger.debug( "Invalid IPN from paypal with data %s", args )
                mail_managers( 'PayPal Failure', 'Data object %s' % (data,) )
                ret = self.invalid_ipn(data)

        if ret:
            return ret
        else:
            #data['valid'] = False
            #data['custom'] = 'uptown1-TB119'
            #data['txn_id'] = 'TEST_TXN_!00'
            #return self.valid_ipn(data) 
            #render_to_response('finished.html', {'data': data} )
            return HttpResponse('Nothing to see here')
            
            
    
    def valid_ipn(self, data):
        """
        data has something like: (See: https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNIntro#id091F0M006Y4 )
            {
                'business': 'info@polyspeeddating.com',
                'charset': 'windows-1252',
                'cmd': '_notify-validate',
                'first_name': '',
                'last_name': '',
                'mc_currency': 'USD',
                'mc_fee': '0.01',
                'mc_gross': '0.01',
                'notify_version': '2.6',
                'payer_business_name': '...',
                'payer_email': 'payer@example.com',
                'payer_id': 'paypal id',
                'payer_status': 'verified',
                'payment_date': '11:45:00 Jan 30, 2011 PDT',
                'payment_fee': '',
                'payment_gross': '',
                'payment_status': 'Completed',
                'payment_type': 'instant',
                'receiver_email': 'info@polyspeeddating.com',
                'receiver_id': 'S8XGHLYDW9T3S',
                'residence_country': 'US',
                'txn_id': '61E67681CH3238416',
                'txn_type': 'express_checkout',
                'verify_sign': 'AtkOfCXbDm2hu0ZELryHFjY-Vb7PAUvS'
                'custom': 'uptown1-LM101'
            }
        """
        # do something with all this data.
        viewslogger.debug(" using data: %s", data)

        if 'custom' in data:
            status = data['payment_status']
            if status != 'Completed':
                viewslogger.debug(" got non-completed paypal IPN with status: %s", status)
                return HttpResponse('Ignoring ' + status + ' response from paypal.')
            
            ec = data['custom']
            ec = ec.split( '-' )
            if len(ec) == 2:
                data['psdid'] = ec[1]
                data['event'] = ec[0]

                #find regrecord for psdid and event:
                viewslogger.debug(" getting regrecord for %s, %s", ec[1], ec[0])
                paidreg = RegRecord.objects.filter(psdid=ec[1], event=ec[0])
                if len(paidreg) == 0:
                    # no regrecord found or invalid psdid.
                    # TODO: log and mail admins...
                    viewslogger.debug(" could not find regrecord for %s", data)
                    mail_managers( 'PayPal Failure: could not find psdid for payment', 'Data object %s' % (data,) )
                else:
                    viewslogger.debug(" updating regrecord for %s", ec[1])
                    rr = paidreg[0]
                    rr.paid = True
                    rr.addNote( "paypal transation id: " + data['txn_id'] )
                    rr.save()
                    viewslogger.debug( "going to send mail to managers about this transaction" )
                    email_bod=render_to_response( 'payment_email.txt', locals() )
                    mail_managers( 'PayPal Payment for %s' % (rr.psdid,), email_bod.content )
            else:
                viewslogger.debug("invalid custom field")
                mail_managers( 'PayPal Failure: invalid custom field (or no custom field)', 'Data object %s' % (data,) )        
        else:
            viewslogger.debug("missing custom field")
            mail_managers( 'PayPal Failure: invalid custom field (or no custom field)', 'Data object %s' % (data,) )                    

        return render_to_response('finished.html', {'data': data, 'valid':True} )


    
    def invalid_ipn(self, data):
        # Log and bring out Reason?.
        return render_to_response('finished.html', {'data': data, 'valid':False} )




